﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Media;
using NLog;
using iNet.IO;
using iNet.Media.Imaging.Exif;
using iNet.Media.Xmp;

namespace iNet.Media.Imaging
{
	/// <summary>
	/// 提供影像編碼解碼器及相關功能。
	/// </summary>
	public static class ImageCodecs
	{
		#region 欄位
		static readonly Dictionary<IMediaFormat, ImageDecodeSupportStates> _DecodeSupportStates = new Dictionary<IMediaFormat, ImageDecodeSupportStates>();
		static readonly List<IImageDecodeTaskFactory> _DecodeTaskFactories = new List<IImageDecodeTaskFactory>();
		static readonly Dictionary<string, List<IImageDecodeTaskFactory>> _DecodeTaskFactories_By_Extension = new Dictionary<string, List<IImageDecodeTaskFactory>>(PathComparer.Default);
		static readonly Dictionary<IMediaFormat, List<IImageDecodeTaskFactory>> _DecodeTaskFactories_By_Format = new Dictionary<IMediaFormat, List<IImageDecodeTaskFactory>>();
		static readonly Dictionary<IMediaFormat, ImageEncodeSupportStates> _EncodeSupportStates = new Dictionary<IMediaFormat, ImageEncodeSupportStates>();
		static readonly List<IImageEncodeTaskFactory> _EncodeTaskFactories = new List<IImageEncodeTaskFactory>();
		static readonly Dictionary<IMediaFormat, List<IImageEncodeTaskFactory>> _EncodeTaskFactories_By_Format = new Dictionary<IMediaFormat, List<IImageEncodeTaskFactory>>();
		static readonly Dictionary<IMediaFormat, bool> _ExifEncodingSupportStates = new Dictionary<IMediaFormat, bool>();
		static readonly List<IFastMediaFormatRecognizer> _FastFormatRecognizers = new List<IFastMediaFormatRecognizer>();
		static readonly Logger _Logger = LogManager.GetLogger("ImageCodecs");
		static volatile int _MinMediaHeaderSize;
		static volatile int _SourceLockTimeout = 5000;
		static readonly Dictionary<IMediaFormat, bool> _XmpEncodingSupportStates = new Dictionary<IMediaFormat, bool>();
		#endregion
		#region 靜態建構子
		static ImageCodecs()
		{
			//建立預設解碼工作工廠
			AddDecodeTaskFactory(new BmpImageDecodeTaskFactory());
			AddDecodeTaskFactory(new Cr2ImageDecodeTaskFactory());
			AddDecodeTaskFactory(new DngImageDecodeTaskFactory());
			AddDecodeTaskFactory(new GifImageDecodeTaskFactory());
			AddDecodeTaskFactory(new IcoImageDecodeTaskFactory());
			AddDecodeTaskFactory(new JpegImageDecodeTaskFactory());
			AddDecodeTaskFactory(new NefImageDecodeTaskFactory());
			AddDecodeTaskFactory(new OrfImageDecodeTaskFactory());
			AddDecodeTaskFactory(new PefImageDecodeTaskFactory());
			AddDecodeTaskFactory(new PngImageDecodeTaskFactory());
			AddDecodeTaskFactory(new SrfImageDecodeTaskFactory());
			AddDecodeTaskFactory(new TiffImageDecodeTaskFactory());

			//建立預設編碼工作工廠
			AddEncodeTaskFactory(new BmpImageEncodeTaskFactory());
			AddEncodeTaskFactory(new GifImageEncodeTaskFactory());
			AddEncodeTaskFactory(new JpegImageEncodeTaskFactory());
			AddEncodeTaskFactory(new PngImageEncodeTaskFactory());
			AddEncodeTaskFactory(new TiffImageEncodeTaskFactory());
		}
		#endregion
		#region AddDecodeTaskFactory
		/// <summary>
		/// 將新的影像解碼工作工廠加入集合。
		/// </summary>
		/// <param name="factory">影像解碼工作工廠。</param>
		/// <exception cref="ArgumentException">factory 是無效的工廠。</exception>
		/// <exception cref="ArgumentNullException">factory 為 Null (Visual Basic 為 Nothing)。</exception>
		public static void AddDecodeTaskFactory(IImageDecodeTaskFactory factory)
		{
			//確認參數
			if (factory == null)
				throw new ArgumentNullException("factory");

			//取得工廠資訊
			IMediaFormat format = factory.DecodingFormat;
			if (format == null)
				throw new ArgumentException();
			string[] extensions = format.FileNameExtensions;

			//加入集合
			bool isNewFormat;
			List<string> newExtensions = new List<string>();
			lock (_DecodeTaskFactories)
			{
				//加入一般集合
				_DecodeTaskFactories.Add(factory);

				//清除快取
				_DecodeSupportStates.Remove(format);

				//加入格式連結集合
				List<IImageDecodeTaskFactory> list;
				if (!_DecodeTaskFactories_By_Format.TryGetValue(format, out list))
				{
					list = new List<IImageDecodeTaskFactory>();
					list.Add(factory);
					_DecodeTaskFactories_By_Format[format] = list;
					isNewFormat = true;
				}
				else
				{
					list.Add(factory);
					isNewFormat = false;
				}

				//加入副檔名連結集合
				for (int i = extensions.Length - 1; i >= 0; --i)
				{
					string ext = extensions[i];
					if (!_DecodeTaskFactories_By_Extension.TryGetValue(ext, out list))
					{
						list = new List<IImageDecodeTaskFactory>();
						list.Add(factory);
						_DecodeTaskFactories_By_Extension[ext] = list;
						newExtensions.Add(ext);
					}
					else
						list.Add(factory);
				}

				//加入快速格式識別器集合
				IFastMediaFormatRecognizer recognizer = (factory as IFastMediaFormatRecognizer);
				if (recognizer != null)
				{
					//加入集合
					_FastFormatRecognizers.Add(recognizer);

					//更新最小標頭大小
					int headerSize = recognizer.MediaHeaderSize;
					if (headerSize > _MinMediaHeaderSize)
						_MinMediaHeaderSize = headerSize;
				}
			}

			//引發事件
			if (isNewFormat)
				FormatAdded.RaiseEvent<DataEventArgs<IMediaFormat>>(null, new DataEventArgs<IMediaFormat>(format));
			for (int i = newExtensions.Count - 1; i >= 0; --i)
				FileNameExtensionAdded.RaiseEvent<DataEventArgs<string>>(null, new DataEventArgs<string>(newExtensions[i]));
		}
		#endregion
		#region AddEncodeTaskFactory
		/// <summary>
		/// 將新的影像編碼工作工廠加入集合。
		/// </summary>
		/// <param name="factory">影像編碼工作工廠。</param>
		/// <exception cref="ArgumentException">factory 是無效的工廠。</exception>
		/// <exception cref="ArgumentNullException">factory 為 Null (Visual Basic 為 Nothing)。</exception>
		public static void AddEncodeTaskFactory(IImageEncodeTaskFactory factory)
		{
			//確認參數
			if (factory == null)
				throw new ArgumentNullException("factory");

			//取得工廠資訊
			IMediaFormat format = factory.EncodingFormat;
			if (format == null)
				throw new ArgumentException();

			//加入集合
			lock (_EncodeTaskFactories)
			{
				//加入一般集合
				_EncodeTaskFactories.Add(factory);

				//清除快取
				_EncodeSupportStates.Remove(format);
				_ExifEncodingSupportStates.Remove(format);
				_XmpEncodingSupportStates.Remove(format);

				//加入格式連結集合
				List<IImageEncodeTaskFactory> list;
				if (!_EncodeTaskFactories_By_Format.TryGetValue(format, out list))
				{
					list = new List<IImageEncodeTaskFactory>();
					list.Add(factory);
					_EncodeTaskFactories_By_Format[format] = list;
				}
				else
					list.Add(factory);
			}
		}
		#endregion
		#region CheckMetadataEncodingSupportState
		static void CheckMetadataEncodingSupportState(IMediaFormat format)
		{
			List<IImageEncodeTaskFactory> factories;
			bool isExifSupported = false;
			bool isXmpSupported = false;
			if (_EncodeTaskFactories_By_Format.TryGetValue(format, out factories))
			{
				for (int i = factories.Count - 1; i >= 0; --i)
				{
					MediaEncodeTask encodeTask = factories[i].CreateEncodeTask(null);
					if (encodeTask != null)
					{
						IMetadata metadata = encodeTask.CreateCompatibleMetadata(null);
						if (metadata is IExifMetadata)
							isExifSupported = true;
						if (metadata is IXmpMetadata)
							isXmpSupported = true;
						if (isExifSupported && isXmpSupported)
							break;
					}
				}
				_ExifEncodingSupportStates[format] = isExifSupported;
				_XmpEncodingSupportStates[format] = isXmpSupported;
			}
		}
		#endregion
		#region CreateDecodeTask
		/// <summary>
		/// 建立影像解碼工作。
		/// </summary>
		/// <param name="fileName">影像檔案路徑。</param>
		/// <returns>影像解碼工作，Null (Visual Basic 為 Nothing) 表示無法支援指定來源的格式。</returns>
		/// <exception cref="ArgumentNullException">fileName 為 Null (Visual Basic 為 Nothing)。</exception>
		public static ImageDecodeTask CreateDecodeTask(string fileName)
		{
			if (fileName == null)
				throw new ArgumentNullException("fileName");
			return CreateDecodeTask((object)fileName, Timeout.Infinite);
		}
		/// <summary>
		/// 建立影像解碼工作。
		/// </summary>
		/// <param name="stream">影像資料流。</param>
		/// <returns>影像解碼工作，Null (Visual Basic 為 Nothing) 表示無法支援指定來源的格式。</returns>
		/// <exception cref="ArgumentNullException">stream 為 Null (Visual Basic 為 Nothing)。</exception>
		public static ImageDecodeTask CreateDecodeTask(Stream stream)
		{
			if (stream == null)
				throw new ArgumentNullException("stream");
			return CreateDecodeTask((object)stream, Timeout.Infinite);
		}
		static ImageDecodeTask CreateDecodeTask(object source, int timeoutMillis)
		{
			//取得來源
			string fileName = (source as string);
			Stream stream = (source as Stream);

			//建立解碼工作
			byte[] mediaHeader = null;
			lock (_DecodeTaskFactories)
			{
				//取得副檔名
				string extension;
				if (fileName != null)
					extension = Path.GetExtension(fileName);
				else
				{
					FileStream fileStream = (stream as FileStream);
					if (fileStream != null)
						extension = Path.GetExtension(fileStream.Name);
					else
						extension = null;
				}

				//取得支援該副檔名的工廠
				HashSet<IImageDecodeTaskFactory> firstFactories = new HashSet<IImageDecodeTaskFactory>();
				if (extension != null)
				{
					List<IImageDecodeTaskFactory> list;
					if (_DecodeTaskFactories_By_Extension.TryGetValue(extension, out list))
					{
						for (int i = list.Count - 1; i >= 0; --i)
							firstFactories.Add(list[i]);
					}
				}

				//開啟資料流
				bool ownsStream = (stream == null);
				if (ownsStream)
				{
					int timeout = _SourceLockTimeout;
					Stopwatch watch = (timeout > 0 ? new Stopwatch() : null);
					if (watch != null)
						watch.Start();
					while (true)
					{
						try
						{
							stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
							break;
						}
						catch (Exception ex)
						{
							if (watch != null && watch.ElapsedMilliseconds < timeout)
							{
								Thread.Sleep(300);
								continue;
							}
							_Logger.Error("CreateDecodeTask() - Cannot open file '" + fileName + "'.", ex);
							return null;
						}
					}
				}

				//建立解碼工作
				try
				{
					//建立媒體儲存
					MediaStorage sourceStorage = (fileName != null ? new MediaStorage(fileName) : new MediaStorage(stream));

					//使用副檔名優先搜尋
					foreach (IImageDecodeTaskFactory factory in firstFactories)
					{
						try
						{
							//確認格式
							IFastMediaFormatRecognizer fastRecognizer = (factory as IFastMediaFormatRecognizer);
							bool isSupportedFormat;
							if (fastRecognizer != null)
							{
								//讀取標頭
								if (mediaHeader == null)
									mediaHeader = ReadMediaHeader(stream);

								//確認格式
								if (mediaHeader != null)
									isSupportedFormat = fastRecognizer.IsSupportedFormat(mediaHeader);
								else
									isSupportedFormat = IsSupportedFormat(factory, stream);
							}
							else
								isSupportedFormat = IsSupportedFormat(factory, stream);

							//建立解碼工作
							if (isSupportedFormat)
							{
								ImageDecodeTask task = factory.CreateDecodeTask(sourceStorage) as ImageDecodeTask;
								if (task != null)
									return task;
							}
						}
						catch
						{ }
					}

					//搜尋其他可用的工廠
					List<IImageDecodeTaskFactory> secondFactories = new List<IImageDecodeTaskFactory>();
					List<IImageDecodeTaskFactory> thirdFactories = new List<IImageDecodeTaskFactory>();
					for (int i = _DecodeTaskFactories.Count - 1; i >= 0; --i)
					{
						IImageDecodeTaskFactory factory = _DecodeTaskFactories[i];
						if (!firstFactories.Contains(factory))
						{
							if (factory is IFastMediaFormatRecognizer)
								secondFactories.Add(factory);
							else
								thirdFactories.Add(factory);
						}
					}

					//使用其他工廠搜尋
					if (secondFactories.Count > 0)
					{
						//讀取標頭
						if (mediaHeader == null)
							mediaHeader = ReadMediaHeader(stream);

						//建立解碼工作
						for (int i = secondFactories.Count - 1; i >= 0; --i)
						{
							IImageDecodeTaskFactory factory = secondFactories[i];
							IFastMediaFormatRecognizer recognizer = (factory as IFastMediaFormatRecognizer);
							if (mediaHeader != null)
							{
								if (recognizer.IsSupportedFormat(mediaHeader))
								{
									ImageDecodeTask task = factory.CreateDecodeTask(sourceStorage) as ImageDecodeTask;
									if (task != null)
										return task;
								}
							}
							else if (IsSupportedFormat(factory, stream))
							{
								ImageDecodeTask task = factory.CreateDecodeTask(sourceStorage) as ImageDecodeTask;
								if (task != null)
									return task;
							}
						}
					}
					for (int i = thirdFactories.Count - 1; i >= 0; --i)
					{
						IImageDecodeTaskFactory factory = thirdFactories[i];
						if (IsSupportedFormat(factory, stream))
						{
							ImageDecodeTask task = factory.CreateDecodeTask(sourceStorage) as ImageDecodeTask;
							if (task != null)
								return task;
						}
					}

					//無法辨識的格式
					return null;
				}
				finally
				{
					//關閉資料流
					if (ownsStream)
						stream.Close();
				}
			}
		}
		#endregion
		#region CreateEncodeTask
		/// <summary>
		/// 建立影像編碼工作。
		/// </summary>
		/// <param name="encodingFormat">影像編碼格式。</param>
		/// <param name="destination">儲存編碼結果的媒體儲存，預設值為 Null (Visual Basic 為 Nothing)。</param>
		/// <returns>影像編碼工作，Null (Visual Basic 為 Nothing) 表示無法支援指定的編碼格式。</returns>
		/// <exception cref="ArgumentNullException">encodingFormat 為 Null (Visual Basic 為 Nothing)。</exception>
		public static ImageEncodeTask CreateEncodeTask(IMediaFormat encodingFormat, MediaStorage destination = null)
		{
			//確認參數
			if (encodingFormat == null)
				throw new ArgumentNullException("encodingFormat");

			//建立編碼工作
			lock (_EncodeTaskFactories)
			{
				List<IImageEncodeTaskFactory> list;
				if (_EncodeTaskFactories_By_Format.TryGetValue(encodingFormat, out list))
				{
					for (int i = list.Count - 1; i >= 0; --i)
					{
						try
						{
							ImageEncodeTask task = (list[i].CreateEncodeTask(destination) as ImageEncodeTask);
							if (task != null)
								return task;
						}
						catch
						{ }
					}
				}
			}

			//無法辨識的格式
			return null;
		}
		#endregion
		#region GetDecodeSupportStates
		/// <summary>
		/// 取得指定影像格式的解碼支援狀態。
		/// </summary>
		/// <param name="format">指定的影像格式。</param>
		/// <returns>解碼支援狀態。</returns>
		/// <exception cref="ArgumentNullException">format 為 Null (Visual Basic 為 Nothing)。</exception>
		public static ImageDecodeSupportStates GetDecodeSupportStates(IMediaFormat format)
		{
			//確認參數
			if (format == null)
				throw new ArgumentNullException("format");

			//確認支援組合
			ImageDecodeSupportStates states = 0;
			lock (_DecodeTaskFactories)
			{
				//取得快取值
				if (_DecodeSupportStates.TryGetValue(format, out states))
					return states;

				//重新確認支援組合
				List<IImageDecodeTaskFactory> factories;
				if (_DecodeTaskFactories_By_Format.TryGetValue(format, out factories))
				{
					for (int i = factories.Count - 1; i >= 0; --i)
					{
						IImageDecodeTaskFactory factory = factories[i];
						MediaDecodeRequests supportedMediaDecodeReqs = factory.SupportedMediaDecodeRequests;
						ImageDecodeRequests supportedImageDecodeReqs = factory.SupportedImageDecodeRequests;
						if ((supportedMediaDecodeReqs & MediaDecodeRequests.DecodeMetadata) != 0)
							states |= ImageDecodeSupportStates.Metadata;
						if ((supportedMediaDecodeReqs & MediaDecodeRequests.DecodeThumbnailImage) != 0)
							states |= ImageDecodeSupportStates.ThumbnailImage;
						if ((supportedImageDecodeReqs & ImageDecodeRequests.DecodeImage) != 0)
							states |= ImageDecodeSupportStates.Image;
						if ((supportedImageDecodeReqs & ImageDecodeRequests.DecodePixelSize) != 0)
							states |= ImageDecodeSupportStates.PixelSize;
					}
				}
				_DecodeSupportStates[format] = states;
			}
			return states;
		}
		#endregion
		#region GetDecodingFormatFileNameExtensions
		/// <summary>
		/// 取得所有支援的影像解碼格式檔案副檔名。
		/// </summary>
		/// <returns>支援的影像解碼格式檔案副檔名。</returns>
		public static string[] GetDecodingFormatFileNameExtensions()
		{
			lock (_DecodeTaskFactories)
			{
				return _DecodeTaskFactories_By_Extension.Keys.ToArray<string>();
			}
			/*
			//取得副檔名
			HashSet<string> extensionSet = new HashSet<string>(PathComparer.Default);
			IMediaFormat[] allFormats = GetDecoderSupportedFormat();
			for (int i = allFormats.Length; i >= 0; --i)
			{
				string[] supportedExtensions = allFormats[i].FileNameExtensions;
				for (int j = supportedExtensions.Length; j >= 0; --j)
					extensionSet.Add(supportedExtensions[j]);
			}

			//回傳
			string[] extensions = new string[extensionSet.Count];
			extensionSet.CopyTo(extensions);
			return extensions;
			*/
		}
		#endregion
		#region GetDecodingFormats
		/// <summary>
		/// 取得所有支援的影像解碼格式。
		/// </summary>
		/// <returns>支援的影像解碼格式。</returns>
		public static IMediaFormat[] GetDecodingFormats()
		{
			lock (_DecodeTaskFactories)
			{
				return _DecodeTaskFactories_By_Format.Keys.ToArray<IMediaFormat>();
			}
			/*
			lock (_CodecRefCounters)
			{
				IMediaFormat[] formats = new IMediaFormat[_Decoders.Count];
				int index = 0;
				foreach (IImageDecoder decoder in _Decoders)
					formats[index++] = decoder.SupportedFormat;
				return formats;
			}
			*/
		}
		#endregion
		#region GetEncodeSupportStates
		/// <summary>
		/// 取得指定影像格式的編碼支援狀態。
		/// </summary>
		/// <param name="format">指定的影像格式。</param>
		/// <returns>編碼支援狀態。</returns>
		/// <exception cref="ArgumentNullException">format 為 Null (Visual Basic 為 Nothing)。</exception>
		public static ImageEncodeSupportStates GetEncodeSupportStates(IMediaFormat format)
		{
			//確認參數
			if (format == null)
				throw new ArgumentNullException("format");

			//確認支援組合
			ImageEncodeSupportStates states;
			lock (_EncodeTaskFactories)
			{
				//使用快取值
				if (_EncodeSupportStates.TryGetValue(format, out states))
					return states;

				//重新確認支援組合
				List<IImageEncodeTaskFactory> factories;
				if (_EncodeTaskFactories_By_Format.TryGetValue(format, out factories))
				{
					states = 0;
					for (int i = factories.Count - 1; i >= 0; --i)
					{
						IImageEncodeTaskFactory factory = factories[i];
						MediaEncodeRequests mediaEncodeReqs = factory.SupportedMediaEncodeRequests;
						ImageEncodeRequests imageEncodeReqa = factory.SupportedImageEncodeRequests;
						if ((mediaEncodeReqs & MediaEncodeRequests.EncodeMetadata) != 0)
							states |= ImageEncodeSupportStates.Metadata;
						if ((imageEncodeReqa & ImageEncodeRequests.EncodeImage) != 0)
							states |= ImageEncodeSupportStates.Image;
					}
					_EncodeSupportStates[format] = states;
				}
			}
			return states;
		}
        #endregion
		#region GetEncodingFormats
		/// <summary>
		/// 取得所有支援的影像編碼格式。
		/// </summary>
		/// <returns>支援的影像編碼格式。</returns>
		public static IMediaFormat[] GetEncodingFormats()
		{
			lock (_EncodeTaskFactories)
			{
				return _EncodeTaskFactories_By_Format.Keys.ToArray<IMediaFormat>();
			}
		}
		#endregion
		#region GetFormatFromFileNameExtension
		/// <summary>
		/// 取得支援指定副檔名的影像格式。
		/// </summary>
		/// <param name="extension">指定的副檔名。</param>
		/// <returns>支援指定副檔名的影像格式。</returns>
		/// <exception cref="ArgumentNullException">extension 為 Null (Visual Basic 為 Nothing)。</exception>
		public static IMediaFormat GetFormatFromFileNameExtension(string extension)
		{
			//確認參數
			if (extension == null)
				throw new ArgumentNullException("extension");

			//搜尋格式
			lock (_DecodeTaskFactories)
			{
				List<IImageDecodeTaskFactory> list;
				if (_DecodeTaskFactories_By_Extension.TryGetValue(extension, out list))
				{
					HashSet<IMediaFormat> formats = new HashSet<IMediaFormat>();
					for (int i = list.Count - 1; i >= 0; --i)
					{
						IMediaFormat format = list[i].DecodingFormat;
						if (format != null)
							return format;
					}
				}
			}
			return null;
		}
		#endregion
		#region GetFormatsFromFileNameExtension
		/// <summary>
		/// 取得所有支援指定副檔名的影像格式。
		/// </summary>
		/// <param name="extension">指定的副檔名。</param>
		/// <returns>支援指定副檔名的影像格式。</returns>
		/// <exception cref="ArgumentNullException">extension 為 Null (Visual Basic 為 Nothing)。</exception>
		public static IMediaFormat[] GetFormatsFromFileNameExtension(string extension)
		{
			//確認參數
			if (extension == null)
				throw new ArgumentNullException("extension");

			//搜尋格式
			lock (_DecodeTaskFactories)
			{
				List<IImageDecodeTaskFactory> list;
				if (_DecodeTaskFactories_By_Extension.TryGetValue(extension, out list))
				{
					HashSet<IMediaFormat> formats = new HashSet<IMediaFormat>();
					for (int i = list.Count - 1; i >= 0; --i)
						formats.Add(list[i].DecodingFormat);
				}
			}
			return new IMediaFormat[0];
		}
		#endregion
		#region IsExifMetadataEncodingSupported
		/// <summary>
		/// 確認指定的影像格式是否支援 EXIF 中繼資料編碼。
		/// </summary>
		/// <param name="format">指定的影像格式。</param>
		/// <returns>是否支援 EXIF 中繼資料編碼。</returns>
		/// <exception cref="ArgumentNullException">format 為 Null (Visual Basic 為 Nothing)。</exception>
		public static bool IsExifMetadataEncodingSupported(IMediaFormat format)
		{
			bool isSupported;
			lock (_EncodeTaskFactories)
			{
				if (!_ExifEncodingSupportStates.TryGetValue(format, out isSupported))
				{
					CheckMetadataEncodingSupportState(format);
					_ExifEncodingSupportStates.TryGetValue(format, out isSupported);
				}
			}
			return isSupported;
		}
		#endregion
        #region IsImageFileName
        /// <summary>
		/// 確認指定的檔案名稱是否為影像檔案名稱。
		/// </summary>
		/// <param name="fileName">指定的檔案名稱。</param>
		/// <returns>True 表示該名稱為影像檔案名稱，False 表示不是。</returns>
		public static bool IsImageFileName(string fileName)
		{
			//確認參數
			if (string.IsNullOrEmpty(fileName))
				return false;

			//取得副檔名
			string extension = Path.GetExtension(fileName);
			if (string.IsNullOrEmpty(extension))
				return false;

			//確認是否有解碼器
			lock (_DecodeTaskFactories)
			{
				return _DecodeTaskFactories_By_Extension.ContainsKey(extension);
			}
		}
		#endregion
		#region IsSupportedFormat
		static bool IsSupportedFormat(IMediaFormatRecognizer recognizer, Stream stream)
		{
			//確認格式
			long initialPosition = -1;
			bool result;
			try
			{
				//儲存目前讀取位置
				initialPosition = stream.Position;

				//確認格式
				result = recognizer.IsSupportedFormat(stream);
			}
			catch (Exception ex)
			{
				_Logger.Error("IsSupportedFormat() - Fail to check media format.", ex);
				result = false;
			}
			finally
			{
				//恢復讀取位置
				try
				{
					stream.Position = initialPosition;
				}
				catch (Exception ex)
				{
					_Logger.Error("IsSupportedFormat() - Fail to reset stream position.", ex);
					result = false;
				}
			}
			return result;
		}
		#endregion
		#region IsXmpMetadataEncodingSupported
		/// <summary>
		/// 確認指定的影像格式是否支援 XMP 中繼資料編碼。
		/// </summary>
		/// <param name="format">指定的影像格式。</param>
		/// <returns>是否支援 XMP 中繼資料編碼。</returns>
		/// <exception cref="ArgumentNullException">format 為 Null (Visual Basic 為 Nothing)。</exception>
		public static bool IsXmpMetadataEncodingSupported(IMediaFormat format)
		{
			bool isSupported;
			lock (_EncodeTaskFactories)
			{
				if (!_XmpEncodingSupportStates.TryGetValue(format, out isSupported))
				{
					CheckMetadataEncodingSupportState(format);
					_XmpEncodingSupportStates.TryGetValue(format, out isSupported);
				}
			}
			return isSupported;
		}
		#endregion
		#region ReadMediaHeader
		static byte[] ReadMediaHeader(Stream stream)
		{
			//確認狀態
			if (_MinMediaHeaderSize <= 0)
				return new byte[0];

			//讀取標頭
			long initialPosition = -1;
			byte[] header;
			try
			{
				//儲存目前讀取位置
				try
				{
					if (stream.CanSeek)
						initialPosition = stream.Position;
				}
				catch
				{ }

				//讀取資料
				byte[] buffer = new byte[_MinMediaHeaderSize];
				int readCount = stream.Read(buffer, 0, _MinMediaHeaderSize);

				//回傳
				if (readCount == _MinMediaHeaderSize)
					return buffer;
				if (readCount > 0)
				{
					byte[] newBuffer = new byte[readCount];
					Array.Copy(buffer, 0, newBuffer, 0, readCount);
					header = newBuffer;
				}
				else
					header = new byte[0];
			}
			catch (Exception ex)
			{
				_Logger.Error("ReadMediaHeader() - Fail to read media header.", ex);
				header = new byte[0];
			}
			finally
			{
				//恢復讀取位置
				try
				{
					if (initialPosition >= 0)
						stream.Position = initialPosition;
				}
				catch (Exception ex)
				{
					_Logger.Error("ReadMediaHeader() - Fail to reset stream position.", ex);
					header = new byte[0];
				}
			}
			return header;
		}
		#endregion
		#region SourceLockTimeout
		/// <summary>
		/// 取得或設定預設鎖定媒體儲存來源的最長嘗試時間，單位為毫秒。零表示失敗後立即返回，預設值為 5000。
		/// </summary>
		public static int SourceLockTimeout
		{
			get
			{
				return _SourceLockTimeout;
			}
			set
			{
				if (value < 0)
					throw new ArgumentOutOfRangeException();
				_SourceLockTimeout = value;
			}
		}
		#endregion
		#region UpdateMinMediaHeaderSize
		static void UpdateMinMediaHeaderSize()
		{
			_MinMediaHeaderSize = 0;
			foreach (IFastMediaFormatRecognizer recognizer in _FastFormatRecognizers)
			{
				int headerSize = recognizer.MediaHeaderSize;
				if (headerSize > _MinMediaHeaderSize)
					_MinMediaHeaderSize = headerSize;
			}
		}
		#endregion
		#region 事件
		/// <summary>
		/// 發生在新的檔案副檔名支援後。
		/// </summary>
		public static event EventHandler<DataEventArgs<string>> FileNameExtensionAdded;
		/// <summary>
		/// 發生在檔案副檔名不再支援後。
		/// </summary>
		public static event EventHandler<DataEventArgs<string>> FileNameExtensionRemoved;
		/// <summary>
		/// 發生在新的影像格式支援後。
		/// </summary>
		public static event EventHandler<DataEventArgs<IMediaFormat>> FormatAdded;
		/// <summary>
		/// 發生在現有的影像格式不再支援後。
		/// </summary>
		public static event EventHandler<DataEventArgs<IMediaFormat>> FormatRemoved;
		#endregion
	}
	#region ImageDecodeSupportStates
	/// <summary>
	/// 表示影像解碼的支援組合。
	/// </summary>
	[Flags]
	public enum ImageDecodeSupportStates
	{
		/// <summary>
		/// 解碼影像。
		/// </summary>
		Image = 0x1,
		/// <summary>
		/// 解碼縮圖。
		/// </summary>
		ThumbnailImage = 0x2,
		/// <summary>
		/// 解碼中繼資料。
		/// </summary>
		Metadata = 0x4,
		/// <summary>
		/// 解碼像素大小。
		/// </summary>
		PixelSize = 0x8,
	}
	#endregion
	#region ImageEncodeSupportStates
	/// <summary>
	/// 表示影像編碼的支援組合。
	/// </summary>
	[Flags]
	public enum ImageEncodeSupportStates
	{
		/// <summary>
		/// 編碼影像。
		/// </summary>
		Image = 0x1,
		/// <summary>
		/// 編碼中繼資料。
		/// </summary>
		Metadata = 0x2,
	}
	#endregion
}
